#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTextStream>
#include <stdio.h>
#include <unistd.h>
#include "ftdi/ftspi.h"
#include "qhexedit/qhexedit.h"


MainWindow::MainWindow(QByteArray *filename)
{
    this->argFileName = filename;
    this->close();
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow), timer(new QTimer), diodorSpi(NULL),  dataFile(new QFile("out.raw"))
{
    this->argFileName = new QByteArray;
    ui->setupUi(this);
//-------HexEdits
    this->hexeditProgram = new QHexEdit(this);
    this->hexeditData = new QHexEdit(this);
    QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom,this->ui->graphArea);
    layout->addWidget(this->hexeditProgram);
    layout->addWidget(this->hexeditData);
    this->ui->graphArea->setLayout(layout);

//-------SPI----------------------
    this->spi = new FtSpi ( );
    this->timer = new QTimer();

//---------GUI signals-------------
    connect(this->ui->buttonProcessGo, SIGNAL(clicked()),SLOT(startProcessClicked()));
    connect(this->ui->actionProgramOpen,SIGNAL(triggered()),SLOT(fileOpen()));
    connect(this->ui->actionProgramSave,SIGNAL(triggered()),SLOT(fileSave()));
    connect(this->ui->action_Open,SIGNAL(triggered()),SLOT(fileOpen()));
    connect(this->ui->action_FileSave,SIGNAL(triggered()),SLOT(fileSave()));
    connect(this->ui->action_Exit,SIGNAL(triggered()),SLOT(close()));

    connect(this->timer,SIGNAL(timeout()),SLOT(on_pushButton_clicked()));

}
MainWindow::~MainWindow()
{
    this->dataFile->close();
    delete this->dataFile;
    delete this->hexeditData;
    delete this->hexeditProgram;
    delete this->ui;
    qDebug()<<"Deinit FT";
    this->spi->deInit();
}


//--------------------------------------------------------------------------------
//------------------------------SLOTS---------------------------------------------
//--------------------------------------------------------------------------------
void MainWindow::startProcessClicked()
{
    if (this->spi->isInited())
    {
        this->spi->deInit();
        this->ui->groupGPIO->setEnabled(false);
        this->ui->groupSPI->setEnabled(false);
        this->ui->frameUsbSetting->setEnabled(true);
    }
    else
    {
        qDebug()<< "Start";
       //Инициализация USB
        this->spi->setUsbSetting(
                this->ui->lineUsbVendor->text().toInt(0,16), //Vendor
                this->ui->lineUsbProduct->text().toInt(0,16), // Product
                this->ui->listInterface->currentIndex().row() // Interface
                );
        if (!this->spi->usbInit())
        {
            qDebug() << "Error initing!"<< this->spi->getError();
            qErrnoWarning("Error!");
        }
        this->ui->groupGPIO->setEnabled(true);
        this->ui->groupSPI->setEnabled(true);
        this->ui->frameUsbSetting->setEnabled(false);

    }
}


/*----------------------------------------------------------------------------------------------------------------------------
 *----------------------------------------------------------FILE FIUNCTIONS---------------------------------------------------
 *----------------------------------------------------------------------------------------------------------------------------
 */

void MainWindow::fileOpen()
{
    QString filename = QFileDialog::getOpenFileName(this,"Open...");
    QFile *file = new QFile(filename);
    if (this->sender() == this->ui->actionProgramSave)
    {
        file->open(QIODevice::ReadOnly);
        this->hexeditProgram->setData(file->readAll());
        file->close();
        qDebug() << "Program";
    }
    else
    {
        file->open(QIODevice::ReadOnly);
        this->hexeditData->setData(file->readAll());
        file->close();
        qDebug() << "Data";
    }
}
void MainWindow::fileSave()
{
    QString filename = QFileDialog::getSaveFileName(this,"Save...");
    QFile *file = new QFile(filename);
    if (this->sender() == this->ui->actionProgramOpen)
    {
        file->open(QIODevice::WriteOnly);
        file->write(this->hexeditProgram->data());
        file->close();
        qDebug() << "Program";
    }
    else
    {
        file->open(QIODevice::WriteOnly);
        file->write(this->hexeditData->data());
        file->close();
        qDebug() << "Data";
    }
    delete file;
}

void MainWindow::on_pushButton_clicked()
{
    this->timer->stop();
    this->timer->start(500);

    QByteArray bar = this->hexeditData->data();
    bar.append((char)this->spi->readIOLowBits());
    this->hexeditData->setData(bar);

}

void MainWindow::on_buttonSetDirection_clicked()
{
    uint8_t lDirection = this->ui->lineLowDirection->text().mid(2).toInt(0,2);;
    uint8_t hDirection = this->ui->lineHightDirection->text().mid(2).toInt(0,2);;
    if (!this->spi->setIODirection(lDirection,hDirection))
    {
        qDebug()<< "Error setting state: "<< this->spi->getError();
    }
}

void MainWindow::on_buttonSetState_clicked()
{
    uint8_t lState = this->ui->lineLowState->text().mid(2).toInt(0,2);;
    uint8_t hState = this->ui->lineHightState->text().mid(2).toInt(0,2);;
    if (!this->spi->setIOBits(lState,hState))
    {
        qDebug()<< "Error setting state: "<< this->spi->getError();
    }

}

void MainWindow::on_buttonReadValue_clicked()
{
    uint8_t lValue = this->spi->readIOLowBits();
    uint8_t hValue = this->spi->readIOHightBits();

    this->ui->lineLowValue->setText(
                QString("0b%1").arg(lValue, 8, 2, QChar('0'))
                );
    this->ui->lineHightValue->setText(
                QString("0b%1").arg(hValue, 8, 2, QChar('0'))
                );
}

void MainWindow::on_buttonSend_clicked()
{
   //Установка частоты
    this->spi->setFrequency(this->ui->frequency->value()*1000);

   //Установка состояния портов
    uint8_t csPin;
    bool csHightPin = false;
    if (this->ui->checkAutoGPIO->isChecked())
    {
        //Выставляем направление портов
        uint8_t direction = this->spi->getIOLowDirection() & ~(0b111);
        direction |= (0b011 | (1 <<csPin));
        this->spi->setIOLowDirection(direction);

      //Выбираем режим SPI
        switch (this->ui->comboSPIMode->currentIndex())
        {
        case 0://11+0
            this->spi->options = 0x01;
            this->spi->setIOLowBit(0,FT_IO_RESET);
            break;
        case 1:
            qDebug()<< "Warning! Bad SPI mode 1 selected.";
            break;
        case 2://10+1
            this->spi->options = 0x04;
            this->spi->setIOLowBit(0,FT_IO_SET);
            break;
        case 3:
            qDebug()<< "Warning! Bad SPI mode 3 selected.";
            break;
        }
      // Устанавливаем CS
        if (this->ui->checkCSDrive->isChecked())
        {
            if (this->ui->comboCSPin->currentIndex()>4) // CS в старшем порте
            {
              csHightPin = true;
              csPin = this->ui->comboCSPin->currentIndex() - 5;
              direction = this->spi->getIOHightDirection() | (1 << csPin);
              this->spi->setIOHightDirection(direction);
              if (this->ui->checkCSLow->isChecked())
                  this->spi->setIOHightBit(csPin,FT_IO_RESET);
              else
                  this->spi->setIOHightBit(csPin,FT_IO_SET);
            }
            else // CS в младшем порте
            {
              csPin = this->ui->comboCSPin->currentIndex() + 3;
              direction = this->spi->getIOLowDirection() | (1 << csPin);
              this->spi->setIOLowDirection(direction);
              if (this->ui->checkCSLow->isChecked())
                  this->spi->setIOLowBit(csPin,FT_IO_RESET);
              else
                  this->spi->setIOLowBit(csPin,FT_IO_SET);
            }
        }

    }
    else
    {
/*        if (this->ui->lineCPHA->text()=="0")
            //this->spi->options = 0x04;
            this->spi->options = 0x00;
        else
            this->spi->options = 0x01;*/
    }
    //this->spi->options |= 0x10;
    this->spi->options |= 0x30;
    //qDebug()<< "Options:"<<this->spi->options;
    uint32_t bufSize = this->hexeditProgram->data().count();
    uint8_t buf[bufSize];
    memcpy(buf,this->hexeditProgram->data().data(),bufSize);
    this->spi->readWrite(buf,bufSize);
    this->hexeditData->data().clear();
    this->hexeditData->setData(QByteArray((char*)buf,bufSize));
  //Отпускаем CS
    if (csHightPin) // CS в старшем порте
    {
      if (this->ui->checkCSLow->isChecked())
          this->spi->setIOHightBit(csPin,FT_IO_SET);
      else
          this->spi->setIOHightBit(csPin,FT_IO_RESET);
    }
    else
    {
        if (this->ui->checkCSLow->isChecked())
            this->spi->setIOLowBit(csPin,FT_IO_SET);
        else
            this->spi->setIOLowBit(csPin,FT_IO_RESET);
    }
}

void MainWindow::on_buttonStrobCS_clicked()
{
    if (this->ui->checkCSDrive->isChecked())
    {
        if (this->ui->comboCSPin->currentIndex()>4) // CS в старшем порте
        {
          uint8_t csPin = this->ui->comboCSPin->currentIndex() - 5;
          uint8_t direction = this->spi->getIOHightDirection() | (1 << csPin);
          this->spi->setIOHightDirection(direction);
          if (this->ui->checkCSLow->isChecked())
          {
              this->spi->setIOHightBit(csPin,FT_IO_RESET);
              this->spi->setIOHightBit(csPin,FT_IO_SET);
          }
          else
          {
              this->spi->setIOHightBit(csPin,FT_IO_SET);
              this->spi->setIOHightBit(csPin,FT_IO_RESET);
          }
        }
        else // CS в младшем порте
        {
          uint8_t csPin = this->ui->comboCSPin->currentIndex() + 3;
          uint8_t direction = this->spi->getIOLowDirection() | (1 << csPin);
          this->spi->setIOLowDirection(direction);
          if (this->ui->checkCSLow->isChecked())
          {
              this->spi->setIOLowBit(csPin,FT_IO_RESET);
              this->spi->setIOLowBit(csPin,FT_IO_SET);
          }
          else
          {
              this->spi->setIOLowBit(csPin,FT_IO_SET);
              this->spi->setIOLowBit(csPin,FT_IO_RESET);
          }
        }
    }
}
